using System;
using System.Collections.Generic;
using UnityEngine;

namespace LFramework
{
    /// <summary>
    /// 状态机
    /// </summary>
    /// <typeparam name="T">FSMManager</typeparam>
    public class Fsm<T> :FsmBase where T : class
    {
        /// <summary>
        /// 状态机拥有者
        /// </summary>
        public T Owner { get; private set; }

        /// <summary>
        /// 当前状态
        /// </summary>
        public FsmState<T> CurrState { get; private set; }

        /// <summary>
        /// 状态字典
        /// </summary>
        private Dictionary<int, FsmState<T>> m_StateDic;

        /// <summary>
        /// 参数字典
        /// </summary>
        private Dictionary<string, VariableBase> m_ParamDic;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="fsmId">状态机编号</param>
        /// <param name="owner">拥有者</param>
        /// <param name="states">状态数组</param>
        public Fsm(int fsmId, T owner, FsmState<T>[] states)
        {
            m_StateDic = new Dictionary<int, FsmState<T>>();
            m_ParamDic = new Dictionary<string, VariableBase>();
            Owner = owner;

            //把状态加入字典
            int len = states.Length;
            for (int i = 0; i < len; i++)
            {
                FsmState<T> state = states[i];
                if (state != null)
                {
                    state.CurrFsm = this;
                    state.OnInit();
                }
                m_StateDic[(sbyte)i] = state;
            }
        }

        private float elapseSeconds;
        internal void OnUpdate()
        {
            if (CurrState != null)
            {
                elapseSeconds += Time.deltaTime;
                CurrState.OnUpdate(elapseSeconds);
            }
        }

        /// <summary>
        /// 获取状态
        /// </summary>
        /// <param name="stateType">状态Type</param>
        /// <returns>状态</returns>
        public FsmState<T> GetState(int stateType)
        {
            FsmState<T> state = null;
            m_StateDic.TryGetValue(stateType, out state);
            return state;
        }

        /// <summary>
        /// 根据Transitions来进行状态切换
        /// </summary>
        /// <param name="newState">目标状态</param>
        /// <param name="info">自定义参数</param>
        /// <returns>切换是否成功</returns>
        public bool ChangeState(int newState)
        {
            if (m_StateDic == null || !m_StateDic.ContainsKey(newState) || m_StateDic[newState] == null)
            {
                Debug.LogError($"BaseStateMachine.ChangeState error! state={newState}");
                return false;
            }

            if (CurrState != null)
            {
                CurrState.OnLeave(newState);
            }
            CurrStateType = newState;
            CurrState = m_StateDic[CurrStateType];

            //进入新状态
            int lastState = CurrStateType;
            CurrStateType = newState;
            CurrState = m_StateDic[newState];
            elapseSeconds = 0;
            CurrState.OnEnter(lastState);
            return true;
        }

        /// <summary>
        /// 设置参数值
        /// </summary>
        /// <typeparam name="TData">参数类型</typeparam>
        public void SetParam<TData>(string key, TData value)
        {
            VariableBase itemBase = null;
            if (m_ParamDic.TryGetValue(key, out itemBase))
            {
                Variable<TData> item = itemBase as Variable<TData>;
                item.Value = value;
            }
            else
            {
                //参数不存在
                Variable<TData> item = new Variable<TData>();
                item.Value = value;
                m_ParamDic[key] = item;
            }
        }
        /// <summary>
        /// 获取参数值
        /// </summary>
        /// <typeparam name="TData">参数类型</typeparam>
        public TData GetParam<TData>(string key)
        {
            VariableBase itemBase = null;
            if (m_ParamDic.TryGetValue(key, out itemBase))
            {
                Variable<TData> item = itemBase as Variable<TData>;
                return item.Value;
            }
            return default(TData);
        }
        private void ResetParam()
        {
            m_ParamDic.Clear();
        }

        /// <summary>
        /// 关闭状态机
        /// </summary>
        public override void Destroy()
        {
            if (CurrState != null)
            {
                CurrState.OnLeave(0);
            }

            foreach (KeyValuePair<int, FsmState<T>> state in m_StateDic)
            {
                if (state.Value == null) continue;
                state.Value.OnDestroy();
            }
            m_StateDic.Clear();
            m_ParamDic.Clear();
        }

    }
}